// ----------------------------------------------------------------------------
// diabindSourceFile.h
// DIA Source File
// ----------------------------------------------------------------------------

#pragma once

// ----------------------------------------------------------------------------

#include "diabindEnumSymbols.h"

// ----------------------------------------------------------------------------

namespace diabind
{

// ----------------------------------------------------------------------------

interface ISourceFile
{
    virtual ~ISourceFile() {}

    virtual DWORD get_uniqueId() = 0;
    virtual std::wstring get_fileName() = 0;
    virtual CEnumSymbolsPtr get_compilands() = 0;
};
typedef boost::shared_ptr< ISourceFile > CSourceFilePtr;

// ----------------------------------------------------------------------------

template< class DiaSourceFileT >
class CSourceFileImpl : public ISourceFile
{
    typedef _com_IIID< DiaSourceFileT, &__uuidof(DiaSourceFileT) > CIiid;
    typedef _com_ptr_t< CIiid > CImplPtr;

public:
    explicit CSourceFileImpl(const CImplPtr &pSourceFile)
        : m_pSourceFile(pSourceFile)
    {
    }

    virtual DWORD get_uniqueId() override
    {
        DWORD RetVal;
        HRESULT hResult = m_pSourceFile->get_uniqueId(&RetVal);
        if (S_OK != hResult)
            throw CException(hResult, "IDiaSourceFile::get_uniqueId");
        return RetVal;
    }
    virtual std::wstring get_fileName() override
    {
        _bstr_t bstrFileName;
        HRESULT hResult = m_pSourceFile->get_fileName(bstrFileName.GetAddress());
        if (S_OK != hResult)
            throw CException(hResult, "IDiaSourceFile::get_fileName");
        return std::wstring(bstrFileName);
    }
    virtual CEnumSymbolsPtr get_compilands() override
    {
        return 
            GetCompilands(
                &DiaSourceFileT::get_compilands,
                "IDiaSourceFile::get_compilands");
    }

protected:
    template< class DiaEnumSymbolsT >
    CEnumSymbolsPtr GetCompilands(
        HRESULT (STDMETHODCALLTYPE DiaSourceFileT::*pMethod)(DiaEnumSymbolsT **),
        const char *szMethodName
    )
    {
        _com_ptr_t< _com_IIID<DiaEnumSymbolsT, &__uuidof(DiaEnumSymbolsT)> > pEnumSymbols;
        HRESULT hResult = (m_pSourceFile->*pMethod)(&pEnumSymbols);
        if (S_OK != hResult)
            throw CException(hResult, szMethodName);

        return CEnumSymbolsPtr( new CEnumSymbolsImpl<DiaEnumSymbolsT>(pEnumSymbols) );
    }

private:
    CImplPtr m_pSourceFile;
};

// ----------------------------------------------------------------------------

}   // namespace diabind

// ----------------------------------------------------------------------------
